
/**
 * @file SolverAmb.hpp
 * Class to compute the PPP Solution.
 *
 * @author shjzhang, 2019/07/22
 * all rights reserved by shjzhang
 */

#ifndef GPSTK_SolverAmb_HPP
#define GPSTK_SolverAmb_HPP

#include "DataStructures.hpp"
#include "Variable.hpp"
#include "Kruskal.hpp"
#include "ARRound.hpp"
#include "ARMLambda.hpp"
#include "Equation.hpp"
#include "Stats.hpp"


namespace gpstk
{
      /**This class solve the receiver and satellite upds using the
       * kruskal algorithm to create a minimum spanning tree, which
       * provide the independent ambiguity datum for ambiguity solution
       * and upd solution.
       *
       * step 1:
       * according to the given sourceSatAmbiData, get all the ambiguity
       * candidate, then create the independent ambiguities
       *
       * step 2:
       * with the independent ambiguities, let's get the upd observables
       * then solve the receiver and satellite upd using the independent
       * updObs
       * 
       * step 3:
       * substitue the receiver and satellite upds into all the MW observations
       * then all the Nw ambiguities will be updated, then the lambda 
       * method is used to fix all the potential ambigities
       *
       * step 4:
       * update the updObs, then solve the upd observations again, to get
       * more precise upds.
       *    
       */

   class SolverAmb 
   {
   public:

          /** Common constructor.
           *
           * @param useNEU   If true, will compute dLat, dLon, dH coordinates;
           *                 if false (the default), will compute dx, dy, dz.
           */
       SolverAmb()
           : firstTime(true),  cutSig(0.15), cutDev(0.2), satSys(SatelliteSystem::Unknown)
       {
           init();
           ambRound.setCutSig(cutSig);
           ambRound.setCutDev(cutDev);
       };

       virtual void setCutDev(double cutDev)
          noexcept(false)
       {
           ambRound.setCutDev(cutDev);
       };

       virtual void setCutSig(double cutSig)
          noexcept(false)
       {
           ambRound.setCutSig(cutSig);
       };

       // set uncalibrated phase bias
       virtual void setSatTypeBiasData(satTypeValueMap& biasData)
       {
           satTypeBiasData = biasData;
       };

       // fix ambiguities using round method
       virtual void Solve(VariableEstDataMap& ambEstData)
          noexcept(false);

       // fix ambiguities using lambda
       virtual void Solve(VariableDataMap& ambData, CovarianceDataMap& ambCovData, int method)
          noexcept(false);


       void computeFloatIntAmbs(VariableDataMap& floatAmbData,
                                VariableDataMap& floatIntAmbData)
          noexcept(false);

       void computeFixedFloatAmbs(VariableDataMap& fixedIntAmbData, 
                                  VariableDataMap& fixedFloatAmbData)
          noexcept(false);


       void fixWithRound(VariableDataMap& ambData,
                         CovarianceDataMap& ambCovData, 
                         VariableDataMap& fixedAmbData);


       void fixWithPAR(VariableDataMap& ambData, 
                       CovarianceDataMap& ambCovData, 
                       VariableDataMap& fixedAmbData);

       double fixWithLambda(VariableDataMap& ambData, 
                           CovarianceDataMap& ambCovData, 
                           VariableDataMap& fixedAmbData);

       virtual VariableDataMap getFloatIntAmbs()
       {
           return currFloatIntAmbData;
       };

       virtual VariableDataMap getFixedIntAmbs()
       {
           return currFixedIntAmbData;
       };

       virtual VariableDataMap getFixedFloatAmbData()
       {
           return currFixedFloatAmbData;
       };

       virtual systemTypeValueMap getRecBias()
          noexcept(false)
       {
           return systemTypeBiasData;
       };


       virtual double getFixingRatio()
          noexcept(false)
       {
           return medianFixingRatio;
       };

          /// Returns a string identifying this object.
       virtual std::string getClassName(void) const;


       virtual void init();


          /// Destructor.
       virtual ~SolverAmb() {};

   private:

       bool firstTime;

       double cutSig;
       double cutDev;

       double medianFixingRatio;

       SatelliteSystem::Systems satSys;
       TypeID ambType;

       satTypeValueMap    satTypeBiasData;
       systemTypeValueMap systemTypeBiasData;
       systemTypeValueMap oldSystemTypeBiasData;

       // type-related data
       VariableSet        ambSet;
       systemTypeVarsMap  systemTypeVars;

       VariableDataMap    currFloatIntAmbData;
       VariableDataMap    currFixedIntAmbData;
       VariableDataMap    currFixedFloatAmbData;

       // Ambiguity method
       ARRound    ambRound;
       ARMLambda  ambMLambda;

   }; // End of class 'SolverAmb'

      //@}

}  // End of namespace gpstk

#endif   // GPSTK_SolverAmb_HPP
